import Event from '@/editor/Event';
import Road from './Road';
import * as THREE from 'three';

/**
 * 道路管理器选项接口
 */
import { Y_LAYERS } from '@/editor/tools/constants';
const CUSTOM_MENU_ID = 'custom-context-menu';

/**
 * 获取鼠标位置
 * @param param - 鼠标事件和射线投射器
 * @returns 鼠标位置的三维向量
 */
function getMousePosition({
  mouseEvent,
  raycaster,
  plane,
  camera,
}: {
  mouseEvent: MouseEvent;
  raycaster: THREE.Raycaster;
  plane: THREE.Plane;
  camera: THREE.PerspectiveCamera;
}): THREE.Vector3 {
  const mouse = new THREE.Vector2();

  const target = mouseEvent.target as HTMLCanvasElement;
  mouse.x = (mouseEvent.offsetX / target.clientWidth) * 2 - 1;
  mouse.y = -(mouseEvent.offsetY / target.clientHeight) * 2 + 1;
  // 更新射线，使其从相机位置出发，沿着鼠标点的方向射出
  raycaster.setFromCamera(mouse, camera);

  // 计算射线与平面的交点
  const intersection = new THREE.Vector3();
  raycaster.ray.intersectPlane(plane, intersection);
  return intersection;
}

/**
 * 创建上下文菜单
 * @param param - 鼠标事件和保存回调
 */
function createContextMenu({
  mouseEvent,
  handleSave,
}: {
  mouseEvent: MouseEvent;
  handleSave: (isClose: boolean, menu: HTMLElement) => () => void;
}): void {
  // 如果已经有右键菜单存在，应该先移除
  const _menu = document.getElementById(CUSTOM_MENU_ID);
  _menu && document.body.removeChild(_menu);
  // 创建右键菜单
  const menu = document.createElement('div');
  menu.setAttribute('id', CUSTOM_MENU_ID);
  menu.style.left = `${mouseEvent.clientX}px`;
  menu.style.top = `${mouseEvent.clientY}px`;

  // 创建菜单项的通用函数
  const createMenuItem = (text: string, callback: () => void): HTMLElement => {
    const item = document.createElement('div');
    item.textContent = text;
    item.addEventListener('click', callback);
    return item;
  };

  // 添加菜单项
  menu.appendChild(createMenuItem('普通保存', handleSave(false, menu)));
  menu.appendChild(createMenuItem('闭合保存', handleSave(true, menu)));

  // 菜单位置修正
  const menuRect = menu.getBoundingClientRect();
  const { clientWidth, clientHeight } = document.documentElement;

  let left = mouseEvent.clientX;
  let top = mouseEvent.clientY;

  // 检查是否会超出右边界
  if (left + menuRect.width > clientWidth) {
    left = Math.max(0, clientWidth - menuRect.width);
  }

  // 检查是否会超出下边界(90%阈值)
  const bottomThreshold = clientHeight * 0.9;
  if (top + menuRect.height > bottomThreshold) {
    top = Math.max(0, bottomThreshold - menuRect.height);
  }

  menu.style.left = `${left}px`;
  menu.style.top = `${top}px`;
  document.body.appendChild(menu);
}

interface RoadManagerEvents {
  [RoadManager.EVENT_ROAD_MANAGER_UPDATE]: (result: { currentRoad: Editor.Road | null; roads: Array<Editor.Road> }) => void;
}

/**
 * 道路管理器类
 */
export default class RoadManager extends Event<RoadManagerEvents> {
  static EVENT_ROAD_MANAGER_UPDATE = 'roadManagerCreate';

  /** 道路列表 */
  roads: Array<Editor.Road> = [];

  /** 配置选项 */
  option: Editor.RoadManagerOption;

  roadEditAbortController: AbortController;

  /** 道路射线投射平面 */
  roadRaycasterPlane: THREE.Plane;

  /**
   * 构造函数
   * @param option - 道路管理器配置选项
   */
  constructor(option: Editor.RoadManagerOption) {
    super();
    this.option = option;
    this.roadRaycasterPlane = new THREE.Plane(new THREE.Vector3(0, Y_LAYERS.ROAD, 0), 0);
    this.roadEditAbortController = new AbortController();
  }

  /** 手动触发UPDATE事件 */
  _manualEmitUpadateEvent = () => {
    this._emitEvent(RoadManager.EVENT_ROAD_MANAGER_UPDATE, {
      currentRoad: this.roads[this.roads.length - 1],
      roads: this.roads,
    });
  };

  /**
   * 创建道路
   * @param roadOption - 道路配置选项
   */
  createRoad(_roadOption: { url: string; scene?: THREE.Scene; yLevel?: number }): void {
    const { field, renderer, raycaster, scene, camera } = this.option;
    const { center, size } = field.getInfo();
    // 视角focus
    this._focusFieldCenter(center);
    /**
     * FIXME: 如何适配尺寸,实际需要根据field模型的size和road模型的size来计算
     */
    const box = renderer.domElement;
    if (!box) return;
    let roadOption = Object.assign({ scene, yLevel: Y_LAYERS.ROAD }, _roadOption);
    // 新增道路
    const road = new Road(roadOption);

    let isSupportPathShow = true;
    this.roadEditAbortController = new AbortController();
    // 启用监听事件
    box.addEventListener(
      'click',
      (mouseEvent: MouseEvent) => {
        const menu = document.getElementById(CUSTOM_MENU_ID);
        menu && document.body.removeChild(menu);
        mouseEvent.preventDefault();

        const { x: clickX, z: clickZ } = getMousePosition({ mouseEvent, camera, raycaster, plane: this.roadRaycasterPlane });
        road.update(new THREE.Vector3(clickX, Y_LAYERS.ROAD, clickZ));
        isSupportPathShow = true;
      },
      {
        signal: this.roadEditAbortController.signal,
      }
    );
    box.addEventListener(
      'mousemove',
      (mouseEvent: MouseEvent) => {
        mouseEvent.preventDefault();
        const { x: clickX, z: clickZ } = getMousePosition({ mouseEvent, camera, raycaster, plane: this.roadRaycasterPlane });
        const newPoint = new THREE.Vector3(clickX, Y_LAYERS.ROAD, clickZ);
        if (road.points.length === 0) {
          road._updateCachePoints(newPoint);
          isSupportPathShow && road.createSupportPath(road.firstCachePoints, true);
        } else {
          isSupportPathShow && road.createSupportPath([newPoint]);
        }
      },
      {
        signal: this.roadEditAbortController.signal,
      }
    );

    box.addEventListener(
      'contextmenu',
      (mouseEvent: MouseEvent) => {
        mouseEvent.preventDefault();
        const handleSave = (isClosed: boolean, menu: HTMLElement) => {
          return () => {
            isSupportPathShow = false;
            // road相关
            road.close(isClosed);
            this.roads.push(road);
            this._emitEvent(RoadManager.EVENT_ROAD_MANAGER_UPDATE, { currentRoad: road, roads: this.roads });
            // 移除三个监听
            this.roadEditAbortController.abort();
            this.roadEditAbortController = null;
            this._unfocusFieldCenter();
            document.body.removeChild(menu);
          };
        };
        createContextMenu({ mouseEvent, handleSave });
      },
      {
        signal: this.roadEditAbortController.signal,
      }
    );
  }

  /**
   * 移除道路
   * @param index - 道路索引
   */
  removeRoad(index: number): void {
    const road = this.roads[index];
    if (!road) return;
    // 如果移除的是正在编辑的道路，则先要接触其与controls的光系
    const { controls } = this.option;
    const controlObject = controls.transformControls.object;
    if (controlObject && controlObject.uuid === road.pathMesh.uuid) {
      controls.detachTransfromControls();
    }
    // 移除road
    this.roads.splice(index, 1);
    road.destroy();
    this._emitEvent(RoadManager.EVENT_ROAD_MANAGER_UPDATE, { currentRoad: null, roads: this.roads });
  }

  /**
   * 聚焦到场地中心
   * @param center - 中心坐标
   */
  _focusFieldCenter(center: THREE.Vector3): void {
    const { controls, camera } = this.option;
    if (!controls || !camera) return;

    const { orbitControls } = controls;
    // TODO: y值需要修改,当前500
    camera.position.set(center.x, 500, center.z);
    orbitControls.target = new THREE.Vector3(center.x, 0, center.z);
    // 只允许在当前投影平面旋转
    orbitControls.minPolarAngle = -Math.PI;
    orbitControls.maxPolarAngle = -Math.PI / 2;
  }

  /**
   * 取消聚焦场地中心
   */
  _unfocusFieldCenter(): void {
    const { controls, camera } = this.option;
    if (!controls || !camera) return;
    const { orbitControls } = controls;
    // 恢复相机默认位置（示例值，根据您的场景调整）
    // camera.position.set(0, 500, 0);

    // 解锁控制器限制
    // orbitControls.target.set(0, 0, 0);
    orbitControls.minPolarAngle = 0;
    orbitControls.maxPolarAngle = Math.PI;
    orbitControls.update();
  }

  /**
   * 销毁道路管理器
   */
  destroy(): void {
    this._removeEvents();
  }
}
